// Functions associated with the FileManager class
//-----------------

//-----------------
// Includes libraries and other files
#include "FileManager.h"
//-----------------

//-----------------
//// CONSTRUCTOR - FileManager
FileManager::FileManager( LPDIRECT3DDEVICE9 device)
	: device_( device)
{}

//// DESTRUCTOR - ~FileManager
FileManager::~FileManager() {}
//-----------------

//-----------------
//// FUNCTION - extract_previous_models
// load in all the known models and store them in the global vector
void FileManager::extract_models_and_audio( std::vector<Mesh>* models) const {
	// Pre-conditions :- none
	assert( true);

	std::ifstream input_file;
	std::string word( "");
	bool not_finished( true);
	input_file.open( (PATH_MODELS+FILE_ASSETS+FILE_EXTENSION), std::ios::in);

	input_file >> word;

	while( not_finished) {
		if( word == OBJECT_MODEL) {
			Mesh temp;

			input_file >> word;

			// if the mesh loads successfully, then add it to the vector
			if( SUCCEEDED( temp.load_mesh( device_, word.c_str())))
				models->push_back( temp);

			// discard all the excess data for the model
			get_sentence( input_file, END);
			input_file >> word;
		}
		else if( word == OBJECT_AUDIO) {
			// ##### NOTE #####
			// loading in audio assets has not yet been implemented
			// ##### NOTE #####
		}
		else
			not_finished = false;

		input_file >> word;
	}

	input_file.close();
}

//// FUNCTION - extract_previous_assets
// load in all the model and audio files that were 'recognised' by the previous execution of the program
void FileManager::extract_previous_assets( std::vector<Mesh>* models, std::list<ModelAsset>& lm, std::list<AudioAsset>& la, std::list<std::string>& li) const {
	// Pre-conditions :- the pointer to the models must be valid
	assert( models != nullptr);

	std::ifstream input_file;
	std::string word( "");
	input_file.open( (PATH_MODELS+FILE_ASSETS+FILE_EXTENSION), std::ios::in);
	input_file >> word;

	// if the end of the external file has not been reached, another object must need extracting
	while( word != END_OF_FILE)
		extract_asset_from_file( models, lm, la, li, input_file, word);

	input_file.close();
}

//// FUNCTION - is_valid_format
// ensure that the format of the file is correct
bool FileManager::is_valid_format( const std::string& file, const std::string& type) const {
	// Pre-conditions :- the type must be valid
	assert( type == "model" || type == "audio");

	if( type == "model") {
		if( file.length() > 2 && (file.substr( file.length()-2) == ".x" || file.substr( file.length()-2) == ".X"))
			return true;
	}
	else if( type == "audio") {
		if( file.length() > 3 && (file.substr( file.length()-3) == ".mp3"))
			return true;
	}

	// if the file extension is invalid then return false
	return false;
}

//// FUNCTION - export_assets_to_file
// save all the useable assets that are saved in the linked lists to an external file so they can be obtained next time the toolset is run
void FileManager::export_assets( std::list<ModelAsset>& lm, std::list<AudioAsset>& la, std::list<std::string>& li) const {
	// Pre-conditions :- none
	assert( true);

	std::ofstream output;

	// open the target file (if it doesn't exist then it'll be created)
	output.open( PATH_MODELS+FILE_ASSETS+FILE_EXTENSION, std::ios::out);

	// add the model assets' information to the file
	for( std::list<ModelAsset>::iterator i( lm.begin()); i != lm.end(); ++i)
		output << OBJECT_MODEL << " " << i->get_file_name() << " " << i->get_asset_name() << " " << END << " " << i->get_asset_type() << "\n";

	// add the audio assets' information to the file
	for( std::list<AudioAsset>::iterator i( la.begin()); i != la.end(); ++i)
		output << OBJECT_AUDIO << " " << i->get_file_name() << " " << i->get_asset_name() << " " << END << "\n";

	// add the list of assets that are to be ignored to the file
	for( std::list<std::string>::iterator i( li.begin()); i != li.end(); ++i)
		output << OBJECT_IGNORE << " " << *i << "\n";

	// insert the keyword to indicate the end of the file and then close the file
	output << END_OF_FILE;
	output.close();
}

//// FUNCTION - export_module_to_file
// save the module to an external file
void FileManager::export_module( std::vector<std::vector<PlacedObject>>& vf, std::vector<std::vector<PlacedObject>>& vm, std::list<AudioAsset>& la, const std::string& file_name) const {
	// Pre-conditions :- the file name must be valid
	assert( file_name != "");

	std::ofstream output;

	// open the target file (if it doesn't exist then it'll be created)
	output.open( PATH_MODULES+file_name+MODULE_EXTENSION, std::ios::out);

	output << LOCATOR_VERSION << " " << versions[versions.size()-2] << " \n";

	// ##### NOTE #####
	// Currently all models will be exported as a WorldObject however, later in development the properties of an object will be tested before being
	// exported and its object tag will change depending on which would be most efficient (e.g. objects that can't be interacted with will only have a
	// mesh and position as that's all it would need and could be put into a class called IncorporealObject).
	// Other information would still need to be exported (for loading the asset into the toolset) but the import function for gameplay would skip over
	// the irrelevant information.
	// ##### NOTE #####

	// ##### NOTE #####
	// Currently only one 'level' can be created, but hopefully multiple levels will be creatable in one module, hence the following.
	output << LOCATOR_LEVEL_TOTAL << " 1 \n";
	output << LOCATOR_LEVEL << " 1 \n";
	// ##### NOTE #####

	// search through the object's array to locate the start and end positions of the player
	bool start( false), end( false);
	for( int i( 0); i < vm.size(); ++i) {
		for( int j( 0); j < vm[i].size(); ++j) {
			if( vm[i][j].get_file_name() == WAYPOINT_START) {
				// send the start position's information to the file
				output << START_POSITION << " " << i << " " << j << " " << vm[i][j] << " " << END << "\n";
				start = true;
				break;
			}
		}
		// exit the loop if the start position has been found
		if( start)
			break;
	}

	// search through the entire array for end positions (to obtain ALL of the end positions)
	for( int i( 0); i < vm.size(); ++i)
		for( int j( 0); j < vm[i].size(); ++j)
			if( vm[i][j].get_file_name() == WAYPOINT_END) {
				// send the end position's information to the file
				output << END_POSITION << " " << i << " " << j << " " << vm[i][j] << " " << END << "\n";
				end = true;
			}

	// only output the level if a start and end position has been found
	if( start && end) {
		// add all the floor tiles and their required information to the file
		for( int i( 0); i < vf.size(); ++i) {
			for( int j( 0); j < vf[i].size(); ++j) {
				// ensure that a floor tile exists at this array position
				if( vf[i][j].get_file_name() != "")
					output << OBJECT_WORLD << " " << i << " " << j << " " << vf[i][j] << " " << END << "\n";
			}
		}

		// add all the objects and their required information to the file
		for( int i( 0); i < vm.size(); ++i) {
			for( int j( 0); j < vm[i].size(); ++j) {
				// ensure that an object exists at this array position and that it's neither the start nor end waypoint
				if( vm[i][j].get_file_name() != "" && vm[i][j].get_file_name() != WAYPOINT_START && vm[i][j].get_file_name() != WAYPOINT_END)
					output << OBJECT_WORLD << " " << i << " " << j << " " << vm[i][j] << " " << END << "\n";
			}
		}

		// ##### NOTE #####
		// audio has not yet been implemented so there's no need to output anything regarding audio
		// ##### NOTE #####
	}
	else
		// indicate that either a start or end position is missing (which means this function shouldn't have been called
		MessageBox( NULL, "Error Code: 009", "FileManager::export_module", MB_OK);

	// signify the end of the file
	output << END_OF_FILE;
}

//// FUNCTION - import_module_to_toolset
// check an external module file's version number to call the correct function for it to be extracted correctly
void FileManager::import_module_to_toolset( std::vector<Mesh>* models, std::vector<std::vector<PlacedObject>>& vf, std::vector<std::vector<PlacedObject>>& vm, std::list<AudioAsset>& la, const int& FLOOR, const std::string& file_name) const {
	// Pre-conditions :- the file name must be valid
	assert( file_name != "");

	std::ifstream input_file;
	std::string word;

	input_file.open( PATH_MODULES+file_name+MODULE_EXTENSION, std::ios::in);

	input_file >> word;

	if( word != LOCATOR_VERSION)
		// if the file doesn't have a version number then it means that the version is 1.0
		import_module_to_toolset_1_0( models, vf, vm, la, FLOOR, input_file);
	else {
		input_file >> word;

		int version( 0);
		for( version; version < versions.size(); ++version)
			if( versions[version] == word)
				break;

		switch( version) {
			case 0:		// version 1.0
				import_module_to_toolset_1_0( models, vf, vm, la, FLOOR, input_file);
				break;
			case 1:		// version 1.1
				import_module_to_toolset_1_1( models, vf, vm, la, FLOOR, input_file);
				break;
			case 2:		// version 1.2
				import_module_to_toolset_1_1( models, vf, vm, la, FLOOR, input_file);
				break;
			default:
				MessageBox( NULL, "Error Code: 010", "FileManager::import_module_to_toolset", MB_OK);
				return;
		}
	}

	input_file.close();
}

//// FUNCTION - import_essential_module_data
// import data such as how many levels are in the modules
void FileManager::import_essential_module_data( const std::string& file_name, int& total_levels) const {
	// Pre-conditions :- the file name must be valid
	assert( file_name != "");

	std::ifstream input_file;
	std::string word( "");

	input_file.open( PATH_MODULES+file_name+MODULE_EXTENSION, std::ios::in);

	// search through the module file until the keyword has been found
	do {
		input_file >> word;
	} while( word != LOCATOR_LEVEL_TOTAL);

	// save the next number as the total number of levels that are to be expected in this module
	input_file >> total_levels;

	input_file.close();
}

//// FUNCTION - import_level_from_module
// check an external module file's version number to call the correct function for it to be extracted correctly
void FileManager::import_level_from_module( std::vector<Mesh>* models, std::vector<WorldObject*>& vm, WorldObject& skybox, std::vector<AudioAsset*>& la, Player* p_player, std::vector<EndPosition>& end_positions, const std::string& file_name, const int& level) const {
	// Pre-conditions :- the file name must be valid
	assert( file_name != "");

	std::ifstream input_file;
	std::string word( "");

	input_file.open( PATH_MODULES+file_name+MODULE_EXTENSION, std::ios::in);

	input_file >> word;

	if( word != LOCATOR_VERSION)
		// if the file doesn't have a version number then it means that the version is 1.0
		import_level_from_module_1_0( models, vm, skybox, la, p_player, end_positions, input_file, level);
	else {
		input_file >> word;

		int version( 0);
		for( version; version < versions.size(); ++version)
			if( versions[version] == word)
				break;

		switch( version) {
			case 0:		// version 1.0
				import_level_from_module_1_0( models, vm, skybox, la, p_player, end_positions, input_file, level);
				break;
			case 1:		// version 1.1
				import_level_from_module_1_1( models, vm, skybox, la, p_player, end_positions, input_file, level);
				break;
			case 2:		// version 1.2
				import_level_from_module_1_1( models, vm, skybox, la, p_player, end_positions, input_file, level);
				break;
			default:
				MessageBox( NULL, "Error Code: 010", "FileManager::import_level_from_module", MB_OK);
				return;
		}
	}

	input_file.close();
}

//// FUNCTION - import_module_to_toolset_1_0
// read an external file's information and load in the required information for it to be edited
void FileManager::import_module_to_toolset_1_0( std::vector<Mesh>* models, std::vector<std::vector<PlacedObject>>& vf, std::vector<std::vector<PlacedObject>>& vm, std::list<AudioAsset>& la, const int& FLOOR, std::ifstream& input_file) const {
	// Pre-conditions :- none
	assert( true);

	std::string word;

	// Module files made by version 1.0 listed how many levels there were and the level number, however
	// it was impossible to actually create multiple levels using the toolset. The following section of
	// code removes the level part of the file so the program can move straight onto extracting the objects.
	// I.e. the first object to be extracted will be the start position.
	do {
		input_file >> word;
	} while( word != START_POSITION);

	while( word != END_OF_FILE) {
		// Audio and waypoints had not been implemented in this version.
		//if( word == OBJECT_AUDIO)
		//else if( word == OBJECT_WAYPOINT)

		if( word == OBJECT_WORLD || word == START_POSITION || word == END_POSITION) {
			PlacedObject temp;
			int i( 0), j( 0);

			// The start position has an additional variable that indicates the player's
			// lookat; this ignores that (the rest of the informations is the same).
			if( word == START_POSITION)
				input_file >> i;

			// get the array position
			input_file >> i;
			input_file >> j;

			input_file >> word;

			for( int k( 0); k < models->size(); ++k)
				if( models->at( k) == word)
					temp.set_mesh( &models->at( k));

			if( temp.get_file_name() != "") {
				float x( 0), y( 0), z( 0);

				// get the object's position
				input_file >> x >> y >> z;
				temp.set_position( x, y, z);

				// get the object's dimensions
				input_file >> x >> y >> z;
				temp.set_dimensions( x, y, z);

				// get the object's rotation
				input_file >> x;
				temp.set_rotation( x);

				// get the object's name
				temp.set_object_name( get_sentence( input_file, END));

				// get the object's type (e.g. Floor, Scenery, Miscellaneous etc.)
				input_file >> x;
				temp.set_object_type( x);

				// get whether the object is breakable
				input_file >> x;
				temp.set_breakable( x);

				// get the object's maximum health
				input_file >> x;
				temp.set_max_health( x);

				// discard the END marker as the asset was valid
				input_file >> word;
			}
			else {
				// skip to the end of this asset if the mesh didn't load properly
				get_sentence( input_file, END);
				get_sentence( input_file, END);
			}

			// add the object to the correct list
			if( temp.get_object_type() == FLOOR)
				vf[i][j] = temp;
			else
				vm[i][j] = temp;
		}

		// get the next asset's keyword
		input_file >> word;
	}
}

//// FUNCTION - import_module_to_toolset_1_1
// read an external file's information and load in the required information for it to be edited
void FileManager::import_module_to_toolset_1_1( std::vector<Mesh>* models, std::vector<std::vector<PlacedObject>>& vf, std::vector<std::vector<PlacedObject>>& vm, std::list<AudioAsset>& la, const int& FLOOR, std::ifstream& input_file) const {
	// Pre-conditions :- none
	assert( true);

	std::string word;

	// ##### NOTE #####
	// Levels need to be implemented.
	// ##### NOTE #####
	do {
		input_file >> word;
	} while( word != START_POSITION);

	while( word != END_OF_FILE) {
		if( word == OBJECT_AUDIO) {
			AudioAsset temp;
			// ##### NOTE #####
			// Audio has yet to be implemented
			// ##### NOTE #####
		}
		else if( word == OBJECT_WAYPOINT) {
			// ##### NOTE #####
			// Waypoints have yet to be implemented
			// ##### NOTE #####
		}
		else if( word == OBJECT_WORLD || word == START_POSITION || word == END_POSITION) {
			PlacedObject temp;
			int i( 0), j( 0);

			// get the array position
			input_file >> i;
			input_file >> j;

			input_file >> word;

			for( int k( 0); k < models->size(); ++k)
				if( models->at( k) == word)
					temp.set_mesh( &models->at( k));

			if( temp.get_file_name() != "") {
				float x( 0), y( 0), z( 0);

				// get the object's position
				input_file >> x >> y >> z;
				temp.set_position( x, y, z);

				// get the object's dimensions
				input_file >> x >> y >> z;
				temp.set_dimensions( x, y, z);

				// get the object's rotation
				input_file >> x;
				temp.set_rotation( x);

				// get the object's name
				temp.set_object_name( get_sentence( input_file, END));

				// get the object's type (e.g. Floor, Scenery, Miscellaneous etc.)
				input_file >> x;
				temp.set_object_type( x);

				// get whether the object is breakable
				input_file >> x;
				temp.set_breakable( x);

				// get the object's maximum health
				input_file >> x;
				temp.set_max_health( x);

				// discard the END marker as the asset was valid
				input_file >> word;
			}
			else {
				// skip to the end of this asset if the mesh didn't load properly
				get_sentence( input_file, END);
				get_sentence( input_file, END);
			}

			// add the object to the correct list
			if( temp.get_object_type() == FLOOR)
				vf[i][j] = temp;
			else
				vm[i][j] = temp;
		}

		// get the next asset's keyword
		input_file >> word;
	}
}

//// FUNCTION - import_level_from_module_1_0
// read an external file's information and load in the required information for it to be played
void FileManager::import_level_from_module_1_0( std::vector<Mesh>* models, std::vector<WorldObject*>& vm, WorldObject& skybox, std::vector<AudioAsset*>& la, Player* p_player, std::vector<EndPosition>& end_positions, std::ifstream& input_file, const int& level) const {
	// Pre-conditions :- none
	assert( true);

	std::string word( "");

	{
		// The modules made in version 1.0 were incapable of setting a certain skybox; so give the map a daytime skybox.
		Mesh m;
		m.load_mesh( device_, "object_skybox_day.X");
		models->push_back( m);
		skybox.set_mesh( &models->at( models->size()-1));
	}

	{
		// search through the module file until the correct level number has been found
		int l( 0);

		while( l != level) {
			// locate where a level number is listed within the module file
			do {
				input_file >> word;
			} while( word != LOCATOR_LEVEL);

			// save the level number so it can be tested
			input_file >> l;
		}
	}

	input_file >> word;

	while( word != END_OF_FILE) {
		if( word == OBJECT_WORLD) {
			WorldObject* temp = new WorldObject;
			*temp = WorldObject();
			float x( 0), y( 0), z( 0);

			// ignore the object's array position
			input_file >> word;
			input_file >> word;

			// save the object's file name
			input_file >> word;

			// Audio had not been implemented in version 1.0.
			//if( word == OBJECT_AUDIO)

			for( int i( 0); i < models->size(); ++i)
				if( models->at( i) == word)
					temp->set_mesh( &models->at( i));

			if( temp->get_file_name() != "") {
				// save the object's location
				input_file >> x >> y >> z;
				temp->set_location( x, y, z);

				// Obtain the object's dimensions from the .X file instead as the dimensions in the module file
				// will be for the toolset.
				//temp->set_dimensions( x, y, z);
				input_file >> x >> y >> z;
				get_asset_dimensions( *temp);

				// save the object's rotation
				input_file >> x;
				temp->set_rotation( x);

				// WorldObject's don't need the name, so ignore it
				get_sentence( input_file, END);

				// discard the object's type
				input_file >> word;

				// get whether the object is breakable
				input_file >> x;
				temp->set_breakable( x);

				// get the object's maximum health
				input_file >> x;
				temp->set_health_maximum( x);

				// discard the END marker as the asset was valid
				input_file >> word;

				// save the object to the vector
				vm.push_back( temp);
			}
			else {
				// if the model didn't load then discard the rest of the object's information...
				get_sentence( input_file, END);
				get_sentence( input_file, END);

				// ... as well as deleting the temp variable
				delete temp;
			}
		}
		else if( word == START_POSITION) {
			float x( 0.0f), y( 0.0f), z( 0.0f);

			// set the orientation of the player
			input_file >> x;
			p_player->set_phi( x);

			// move forward to where the coordinates of the start position are listed
			input_file >> word >> word >> word;

			// save the coordinates and position the player at the CENTER of the 'grid square'
			input_file >> x >> y >> z;
			p_player->set_location( x+(float(GRID_SIZE)/2), y, z+(float(GRID_SIZE)/2));

			// skip through the rest of the START_POSITION information (it's only useful in the toolset)
			get_sentence( input_file, END);
			get_sentence( input_file, END);
		}
		else if( word == END_POSITION) {
			float x( 0.0), y( 0.0), z( 0.0);

			// move forward to where the coordinates of the end position are listed
			input_file >> word >> word >> word;

			// save the coordinates of the end position
			input_file >> x >> y >> z;
			EndPosition temp( x, y, z);

			// ##### NOTE #####
			// The dimensions are not currently changeable; they will always be 5x5x5. This may
			// be changed in a later version and will then need the following lines uncommented.
			//input_file >> x >> y >> z;
			//temp.set_dimensions( x, y, z);
			// ##### NOTE #####

			// add the end position to the vector
			end_positions.push_back( temp);

			// skip through the rest of the END_POSITION information (it's only useful in the toolset)
			get_sentence( input_file, END);
			get_sentence( input_file, END);
		}

		input_file >> word;
	}
}

//// FUNCTION - import_level_from_module_1_1
// read an external file's information and load in the required information for it to be played
void FileManager::import_level_from_module_1_1( std::vector<Mesh>* models, std::vector<WorldObject*>& vm, WorldObject& skybox, std::vector<AudioAsset*>& la, Player* p_player, std::vector<EndPosition>& end_positions, std::ifstream& input_file, const int& level) const {
	// Pre-conditions :- none
	assert( true);

	std::string word( "");

	{
		// ##### NOTE #####
		// Implement a system whereby the user can specify the type of skybox. For now, just give the level a daytime one.
		Mesh m;
		m.load_mesh( device_, "object_skybox_day.X");
		models->push_back( m);
		skybox.set_mesh( &models->at( models->size()-1));
		// ##### NOTE #####
	}

	{
		// search through the module file until the correct level number has been found
		int l( 0);

		while( l != level) {
			// locate where a level number is listed within the module file
			do {
				input_file >> word;
			} while( word != LOCATOR_LEVEL);

			// save the level number so it can be tested
			input_file >> l;
		}
	}

	input_file >> word;

	while( word != END_OF_FILE) {
		if( word == OBJECT_WORLD) {
			WorldObject* temp = new WorldObject;
			*temp = WorldObject();
			float x( 0), y( 0), z( 0);

			// ignore the object's array position
			input_file >> word;
			input_file >> word;

			// save the object's file name
			input_file >> word;

			for( int i( 0); i < models->size(); ++i)
				if( models->at( i) == word)
					temp->set_mesh( &models->at( i));

			if( temp->get_file_name() != "") {
				// save the object's location
				input_file >> x >> y >> z;
				temp->set_location( x, y, z);

				// save the object's dimensions
				input_file >> x >> y >> z;
				temp->set_dimensions( x, y, z);

				// save the object's rotation
				input_file >> x;
				temp->set_rotation( x);

				// WorldObject's don't need the name, so ignore it
				get_sentence( input_file, END);

				// discard the object's type
				input_file >> word;

				// get whether the object is breakable
				input_file >> x;
				temp->set_breakable( x);

				// get the object's maximum health
				input_file >> x;
				temp->set_health_maximum( x);

				// discard the END marker as the asset was valid
				input_file >> word;

				// save the object to the vector
				vm.push_back( temp);
			}
			else {
				// if the model didn't load then discard the rest of the object's information...
				get_sentence( input_file, END);
				get_sentence( input_file, END);

				// ... as well as deleting the temp variable
				delete temp;
			}
		}
		else if( word == OBJECT_AUDIO) {
			// ##### NOTE #####
			// Audio has not yet been implemented
			// ##### NOTE #####
		}
		else if( word == START_POSITION) {
			float lookat( 0), x( 0.0f), y( 0.0f), z( 0.0f);

			// move forward to where the coordinates of the start position are listed
			input_file >> word >> word >> word;

			// save the coordinates and position the player at the CENTER of the 'grid square'
			input_file >> x >> y >> z;
			p_player->set_location( x+(float(GRID_SIZE)/2), y, z+(float(GRID_SIZE)/2));

			// move forward to where the orientation of the player is listed
			input_file >> word >> word >> word;

			// The lookat vector dictates the direction in which the player will be facing.
			// The following are the numbers for looking down the x and z axes:
			//      0.0   = +x direction
			// -D3DX_PI   = -x direction
			//  D3DX_PI/2 = +z direction
			// -D3DX_PI/2 = -z direction
			input_file >> lookat;
			if( lookat == 0)
				lookat = D3DX_PI/2;
			else if( lookat == 90)
				lookat = -D3DX_PI;
			else if( lookat == 180)
				lookat = -D3DX_PI/2;
			else if( lookat == 270)
				lookat = 0;

			// save the player's orientation
			p_player->set_phi( lookat);
			p_player->set_theta( 0.0);

			// skip through the rest of the START_POSITION information (it's only useful in the toolset)
			get_sentence( input_file, END);
			get_sentence( input_file, END);
		}
		else if( word == END_POSITION) {
			float x( 0.0), y( 0.0), z( 0.0);

			// move forward to where the coordinates of the end position are listed
			input_file >> word >> word >> word;

			// save the coordinates of the end position
			input_file >> x >> y >> z;
			EndPosition temp( x, y, z);

			// ##### NOTE #####
			// The dimensions are not currently changeable; they will always be 5x5x5. This may
			// be changed in a later version and will then need the following lines uncommented.
			//input_file >> x >> y >> z;
			//temp.set_dimensions( x, y, z);
			// ##### NOTE #####

			// add the end position to the vector
			end_positions.push_back( temp);

			// skip through the rest of the END_POSITION information (it's only useful in the toolset)
			get_sentence( input_file, END);
			get_sentence( input_file, END);
		}

		input_file >> word;
	}
}

//// FUNCTION - extract_asset_from_file
// test the next word in the file and assign the following data to the correct list
void FileManager::extract_asset_from_file( std::vector<Mesh>* models, std::list<ModelAsset>& lm, std::list<AudioAsset>& la, std::list<std::string>& li, std::ifstream& input_file, std::string& word) const {
	// Pre-conditions :- none
	assert( true);

	if( word == OBJECT_MODEL) {
		ModelAsset temp;
		
		// get the asset's path
		input_file >> word;

		for( int i( 0); i < models->size(); ++i) {
			if( models->at( i) == word)
				temp.set_mesh( &models->at( i));
		}

		if( temp.get_file_name() != "") {
			// get the asset's name...
			word = get_sentence( input_file, END);
			temp.set_asset_name( word);
			// ... and the asset's type...
			int type( 0);
			input_file >> type;
			temp.set_asset_type( type);

			// ... and then add the asset to the list
			lm.push_back( temp);
		}
		else {
			// If the asset fails to load the mesh properly then it'll simply be excluded from
			// the list and not included in the external file when the program is closed.
			// However the following line is needed as its name and type will still remain.
			get_sentence( input_file, END);
			input_file >> word;
		}
	}
	else if( word == OBJECT_AUDIO) {
		AudioAsset temp;

		// get the asset's path...
		input_file >> word;
		temp.set_file_name( word);
		// ... then get the asset's name and then add the asset to the list
		word = get_sentence( input_file, END);
		temp.set_asset_name( word);
		la.push_back( temp);
	}
	else if( word == OBJECT_IGNORE) {
		// get the file's name and add it to the list of items that are to be ignored
		input_file >> word;
		li.push_back( word);
	}

	// acquire the next word in the file
	input_file >> word;
}

//// FUNCTION - get_asset_dimensions
// get the extreme distances in all directions from the asset's .X file to record its dimensions
void FileManager::get_asset_dimensions( WorldObject& a) const {
	// Pre-conditions :- the parameter must have a file name
	assert( a.get_file_name() != (""));

	// ##### NOTE #####
	// This function shouldn't be used for rotating objects in the toolset; they should be rotated
	// using the GRID_SIZE constant. This function could, however, be used to obtain an object's
	// collision dimensions for in-game physics.
	// ##### NOTE #####

	std::ifstream input_file;
	std::string word;
	float max_x( 0), max_y( 0), max_z( 0), min_x( 0), min_y( 0), min_z( 0);

	input_file.open( PATH_MODELS+a.get_file_name(), std::ios::in);

	// "Mesh" is used to locate where all the vertices are listed, but at the beginning of the .X file
	// "Mesh" is used to declare a template. Ignoring the occasion that the program first locates "Mesh"
	// ensures that the next "Mesh"es to be found will definitely have the asset's vertices following.
	while( word != "Mesh" && input_file.get() != input_file.tellg())
		input_file >> word;
	input_file >> word;

	do {
		while( word != "Mesh" && input_file.get() != input_file.tellg())
			input_file >> word;
		input_file >> word;

		// acquire how many vertices are listed - if it's the end of the file then it will acquire 0, skip the for loop and exit the while loop
		int count( 0);
		input_file >> count;

		for( int i( 0); i < count; ++i) {
			float x( 0), y( 0), z( 0);
			if( i != 0)							// if this is the first loop...
				get_word( input_file, ',');		// ... dispose of the ending comma
			else
				get_word( input_file, ';');		// ... else dispose of the colon after the number of vertices is listed

			std::istringstream oss( get_word( input_file, ';') + " " + get_word( input_file, ';') + " " + get_word( input_file, ';'));
			oss >> z >> y >> x;					// the numbers are put into the stringstream in reverse order

			if( x > max_x)
				max_x = x;
			else if( x < min_x)
				min_x = x;
			if( y > max_y)
				max_y = y;
			else if( y < min_y)
				min_y = y;
			if( z > max_z)
				max_z = z;
			else if( z < min_z)
				min_z = z;
		}

	} while( input_file.get() != input_file.tellg());

	input_file.close();

	// set the asset's dimensions
	a.set_dimensions( max_x - min_x, max_y - min_y, max_z - min_z);
}

//// FUNCTION - get_sentence
// extracts a sentence from a text file using a parameter as the end condition
std::string FileManager::get_sentence( std::ifstream& input_file, const std::string& end_condition) const {
	// Pre-conditions :- the end condition must exist
	assert( end_condition != "");

	std::string word( ""), sentence( "");

	input_file >> word;

	// keep extracting the sentence, word by word, until the program reaches the ending marker
	while (word != end_condition) {
		sentence = sentence + " " + word;
		input_file >> word;
	}

	// if there was only one word before the ending marker then sentence will be empty
	if (sentence == "")
		if( word.substr( 0, 1) == " ")
			return( word.substr( 1));
		else
			return( word);
	else
		if( sentence.substr( 0, 1) == " ")
			return( sentence.substr( 1));
		else
			return( sentence);
}

//// FUNCTION - get_word
// extracts a word from a text file using a parameter as the end condition
std::string FileManager::get_word( std::ifstream& input_file, const char& end_condition) const {
	// Pre-conditions :- none
	assert( true);

	char letter;
	std::string word( "");

	input_file >> letter;

	// keep extracting the word, letter by letter, until the program reaches the ending marker
	while (letter != end_condition) {
		word = word + letter;
		input_file >> letter;
	}

	// if there was only one letter before the ending marker then word will be empty
	if (word == "")
		word = letter;
	
	return( word);
}